<template>
  <ElDialog
    v-model="visible"
    title="菜单权限"
    width="520px"
    align-center
    class="el-dialog-border"
    @close="handleClose"
  >
    <ElScrollbar height="70vh">
      <ElTree
        ref="treeRef"
        :data="processedMenuList"
        show-checkbox
        node-key="name"
        :check-strictly="checkStrictly"
        :default-expand-all="isExpandAll"
        :props="defaultProps"
        @check="handleTreeCheck"
      >
        <template #default="{ data }">
          <div style="display: flex; align-items: center">
            <span v-if="data.isAuth">
              {{ data.label }}
            </span>
            <span v-else>{{ defaultProps.label(data) }}</span>
          </div>
        </template>
      </ElTree>
    </ElScrollbar>
    <template #footer>
      <div class="dialog-footer">
        <ElButton @click="outputSelectedData" style="margin-left: 8px">获取选中数据</ElButton>

        <ElButton @click="toggleExpandAll">{{ isExpandAll ? '全部收起' : '全部展开' }}</ElButton>
        <ElButton @click="toggleSelectAll" style="margin-left: 8px">{{
          isSelectAll ? '取消全选' : '全部选择'
        }}</ElButton>
        <ElButton type="primary" @click="savePermission">保存</ElButton>
      </div>
    </template>
  </ElDialog>
</template>

<script setup lang="ts">
  import { useMenuStore } from '@/store/modules/menu'
  import { formatMenuTitle } from '@/router/utils/utils'
  import { editRoleApi } from '@/api/system-manage'

  type RoleListItem = Api.SystemManage.RoleListItem

  interface Props {
    modelValue: boolean
    roleData?: RoleListItem
  }

  interface Emits {
    (e: 'update:modelValue', value: boolean): void
    (e: 'success'): void
  }

  const props = withDefaults(defineProps<Props>(), {
    modelValue: false,
    roleData: undefined
  })

  const emit = defineEmits<Emits>()

  const { menuList } = storeToRefs(useMenuStore())
  const treeRef = ref()
  const isExpandAll = ref(true)
  const isSelectAll = ref(false)
  const checkStrictly = ref(true) // 控制级联选择，回显时为true，用户操作时为false

  /**
   * 弹窗显示状态双向绑定
   */
  const visible = computed({
    get: () => props.modelValue,
    set: (value) => emit('update:modelValue', value)
  })

  /**
   * 菜单节点类型
   */
  interface MenuNode {
    id?: string | number
    name?: string
    label?: string
    meta?: {
      title?: string
      authList?: Array<{
        id?: string | number
        authId?: string | number
        authMark: string
        title: string
        checked?: boolean
      }>
    }
    children?: MenuNode[]
    [key: string]: any
  }

  /**
   * 处理菜单数据，将 authList 转换为树形子节点
   * 递归处理菜单树，将权限列表展开为可选择的子节点
   */
  const processedMenuList = computed(() => {
    const processNode = (node: MenuNode): MenuNode => {
      const processed = { ...node }

      // 如果有 authList，将其转换为子节点
      if (node.meta?.authList?.length) {
        const authNodes = node.meta.authList.map((auth: any) => {
          const authNode = {
            id: auth.id || auth.authId || `${node.id}_${auth.authMark}`, // 优先使用 auth 自己的 id
            name: `${node.name}_${auth.authMark}`,
            label: auth.title,
            authMark: auth.authMark,
            isAuth: true,
            checked: auth.checked || false
          }
          return authNode
        })

        processed.children = processed.children ? [...processed.children, ...authNodes] : authNodes
      }

      // 递归处理子节点
      if (processed.children) {
        processed.children = processed.children.map(processNode)
      }

      return processed
    }

    return (menuList.value as any[]).map(processNode)
  })

  /**
   * 树形组件配置
   */
  const defaultProps = {
    children: 'children',
    label: (data: any) => formatMenuTitle(data.meta?.title) || data.label || ''
  }

  /**
   * 监听弹窗打开，初始化权限数据
   */
  watch(
    () => props.modelValue,
    async (newVal) => {
      if (newVal && props.roleData) {
        // 回显时禁用级联
        checkStrictly.value = true
        // 等待 DOM 更新完成
        await nextTick()
        // 获取并打印 ID->Name 映射表
        // 解析 rules 字段并设置选中状态
        if (props.roleData.rules && treeRef.value) {
          // 将 "1,2,3,4" 格式的字符串转换为数字数组
          const ruleIds = props.roleData.rules
            .split(',')
            .map((id) => Number(id.trim()))
            .filter((id) => !isNaN(id))
          // 将菜单ID转换为树节点的 key（需要根据实际的菜单数据结构匹配）
          const checkedKeys = getNodeKeysByMenuIds(ruleIds)

          // 设置树的选中状态
          treeRef.value.setCheckedKeys(checkedKeys, false)
        }

        // 回显完成后启用级联选择
        await nextTick()
        checkStrictly.value = false
      }
    }
  )

  /**
   * 根据菜单ID列表获取对应的树节点key
   * @param menuIds 菜单ID数组
   * @returns 树节点key数组
   */
  const getNodeKeysByMenuIds = (menuIds: number[]): string[] => {
    const keys: string[] = []
    const matchedIds: number[] = []
    const unmatchedIds: number[] = []

    const traverse = (nodes: MenuNode[]): void => {
      nodes.forEach((node) => {
        // 如果节点的ID在menuIds中，添加其name作为key
        if (node.id && menuIds.includes(Number(node.id))) {
          if (node.name) {
            keys.push(node.name)
            matchedIds.push(Number(node.id))
          }
        }

        // 递归处理子节点
        if (node.children?.length) {
          traverse(node.children)
        }
      })
    }

    traverse(processedMenuList.value)

    // 找出未匹配的ID
    menuIds.forEach((id) => {
      if (!matchedIds.includes(id)) {
        unmatchedIds.push(id)
      }
    })

    return keys
  }

  /**
   * 关闭弹窗并清空选中状态
   */
  const handleClose = () => {
    visible.value = false
    treeRef.value?.setCheckedKeys([])
    checkStrictly.value = true // 重置为严格模式
  }

  /**
   * 保存权限配置
   */
  const savePermission = async () => {
    const tree = treeRef.value
    if (!tree) return

    // 获取全选节点和半选节点
    const checkedNodes = tree.getCheckedNodes()
    const halfCheckedNodes = tree.getHalfCheckedNodes ? tree.getHalfCheckedNodes() : []

    // 合并去重
    const allNodes = [...checkedNodes, ...halfCheckedNodes]
    const idSet = new Set(
      allNodes
        .map((node: any) => node.id)
        .filter((id: any) => id !== undefined && id !== null)
        .map((id: any) => Number(id))
    )
    const selectedIds = Array.from(idSet)

    // 输出逗号拼接的ID字符串
    const idsString = selectedIds.join(',')
    await editRoleApi({
      id: props.roleData?.id,
      name: props.roleData?.name,
      code: props.roleData?.code,
      rules: idsString
    })
    ElMessage.success('权限保存成功')
    emit('success')
    handleClose()
  }

  /**
   * 切换全部展开/收起状态
   */
  const toggleExpandAll = () => {
    const tree = treeRef.value
    if (!tree) return

    const nodes = tree.store.nodesMap
    // 这里保留 any，因为 Element Plus 的内部节点类型较复杂
    Object.values(nodes).forEach((node: any) => {
      node.expanded = !isExpandAll.value
    })

    isExpandAll.value = !isExpandAll.value
  }

  /**
   * 切换全选/取消全选状态
   */
  const toggleSelectAll = () => {
    const tree = treeRef.value
    if (!tree) return

    if (!isSelectAll.value) {
      const allKeys = getAllNodeKeys(processedMenuList.value)
      tree.setCheckedKeys(allKeys)
    } else {
      tree.setCheckedKeys([])
    }

    isSelectAll.value = !isSelectAll.value
  }

  /**
   * 递归获取所有节点的 key
   * @param nodes 节点列表
   * @returns 所有节点的 key 数组
   */
  const getAllNodeKeys = (nodes: MenuNode[]): string[] => {
    const keys: string[] = []
    const traverse = (nodeList: MenuNode[]): void => {
      nodeList.forEach((node) => {
        if (node.name) keys.push(node.name)
        if (node.children?.length) traverse(node.children)
      })
    }
    traverse(nodes)
    return keys
  }

  /**
   * 处理树节点选中状态变化
   * 同步更新全选按钮状态
   */
  // 递归向上处理所有父节点，保证只要下级有半选或选中，父节点都半选且选中
  const handleTreeCheck = (data?: any) => {
    const tree = treeRef.value
    if (!tree) return

    const checkedKeys = tree.getCheckedKeys()
    const allKeys = getAllNodeKeys(processedMenuList.value)
    isSelectAll.value = checkedKeys.length === allKeys.length && allKeys.length > 0

    // 递归向上处理父节点
    function setParentIndeterminate(nodeObj: any) {
      if (!nodeObj || !nodeObj.parent) return
      const parent = nodeObj.parent
      // 只要有子节点被选中或半选，父节点就半选且选中
      const hasCheckedOrIndeterminate = parent.childNodes.some(
        (n: any) => n.checked || n.indeterminate
      )
      if (hasCheckedOrIndeterminate) {
        parent.indeterminate = true
        parent.checked = true
      }
      setParentIndeterminate(parent)
    }

    if (data && data.isAuth) {
      const nodeObj = tree.getNode(data.name)
      const parentNode = nodeObj && nodeObj.parent
      if (parentNode && parentNode.data && !parentNode.data.isAuth) {
        const buttonNodes = parentNode.childNodes.filter((n: any) => n.data.isAuth)
        const allBtnUnchecked = buttonNodes.every((n: any) => !checkedKeys.includes(n.data.name))
        if (allBtnUnchecked) {
          parentNode.indeterminate = true
          parentNode.checked = true
          // 递归向上处理所有父节点
          setParentIndeterminate(parentNode)
        }
      }
    }
  }

  /**
   * 输出选中的权限数据到控制台
   * 用于调试和查看当前选中的权限配置
   */
  const outputSelectedData = () => {
    const tree = treeRef.value
    if (!tree) return
  }
</script>

<style lang="scss" scoped>
  .dialog-footer {
    display: flex;
    gap: 12px;
    justify-content: flex-end;
  }
</style>
